/*************************************************************************
	> File Name: udp_server.c
	> Author: Maureen 
	> Mail: 1437867946@qq.com 
	> Created Time: Mon 11 Jan 2021 09:39:13 PM CST
 ************************************************************************/

#include "head.h"
extern int subfd;

int socket_create_udp(int port) {
    int listener;
    //UDP使用数据报
    if ((listener = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        return -1;
    }
    struct sockaddr_in server;
    //协议族
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    server.sin_port = htons(port); //指定本机的通信port
    
    unsigned long opt = 1;
    //设置端口重用
    setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    if (bind(listener, (struct sockaddr *)&server, sizeof(server)) < 0) { //将socket与server结构体绑定
        return -1;
    }
    return listener;
}

//模拟TCP的accept:接收对端消息并根据类型发送不同的回复消息
int udp_accept(int fd, struct User *user) {
    int new_fd, ret;
    struct sockaddr_in client;
    struct Msg request, response;//报文

    socklen_t len = sizeof(client);
    bzero(&request, sizeof(request));
    bzero(&response, sizeof(response));

    ret = recvfrom(fd, (void *)&request, sizeof(request), 0, (struct sockaddr *)&client, &len);

    if (ret != sizeof(request)) { //收到的报文大小和期望接收到的报文大小不一致,直接回复FIN
        DBG(RED"Login Request Error!\n");
        response.type = CHAT_FIN; 
        strcpy(response.msg, "Login Request Error!");
        sendto(fd, (void *)&response, sizeof(response), 0, (struct sockaddr *)&client, len); //发送给client对应的信息
        return -1;
    } 

    //判断发送消息的用户是否在线
    /*if (check_online(&request)) {
        respnse.type = CHAT_FIN;
        strcpy(respnse.msg, "Already login!");
        sendto(fd, (void *)&response, sizeof(response), 0, (struct sockaddr *)&client, len);
        return -1;
    }*/

    DBG(RED"<Acceptor>"NONE" : request.type = %d\n", request.type);
    
    if (request.type & CHAT_FIN) { //如果收到对方发送的FIN包，则直接结束
        return -1;
    } else if ((request.type & CHAT_SYN) && (request.type & CHAT_ACK)) { //SYNACK报文
        DBG(GREEN"<Acceptor>"NONE" : SYNACK received!\n");

    } else if (request.type != CHAT_SYN) { //判断报文是否为请求报文，即type是否为SYN
        DBG(RED"<Acceptor>"NONE" :Error Request!\n");
        DBG(BLUE"====================\n");
        DBG(YELLOW"type: %d\n", request.type);
        DBG(YELLOW"from: %s\n", request.from);
        DBG(YELLOW"msg: %s\n", request.msg);
        DBG(BLUE"====================\n");
        response.type = CHAT_FIN;
        strcpy(response.msg, "Error Request!");
        sendto(fd, (void *)&response, sizeof(response), 0, (struct sockaddr *)&client, len);
        return -1;
    }
    DBG(GREEN"<Acceptor>"NONE" : [%s] %s...\n", request.from, request.msg);

    //保存发送信息的用户的名称以及相关设置
    strcpy(user->name, request.from);
    user->flag = FL_ONLINE; //标记用户上线
    user->cnt = 5;
    new_fd = udp_connect(&client); //创建一个伪连接，连接接收到的消息的发送方
    if (new_fd < 0) {
        perror("udp_connect");
        return -1;
    }
    user->fd = new_fd;
    char buff[512] = {0};
    sprintf(buff, "%s Login successfully!\n", user->name);
    strcpy(response.msg, buff);
    response.type = CHAT_ACK | CHAT_SYN;
    send(new_fd, (void *)&response, sizeof(response), 0);
    return new_fd;
}
